Flutter UiKitView 嵌入iOS原生View | 您所在的位置:网站首页 › flutter 调用原生view › Flutter UiKitView 嵌入iOS原生View |
本篇文章 中写到的是 flutter 通过 UiKitView 调用了ios 原生的 UILabel 案例。 flutter 通过AndroidView 调用android 原生的TextView 请点击查看这里 flutter 中嵌套使用ios原生组件的流程基本上可以描述为: 1 info.plist文件设置2 ios 端实现原生组件PlatformView提供原生view3 ios 端创建PlatformViewFactory用于生成PlatformView4 ios 端创建FlutterPlugin用于注册原生组件5 flutter 平台嵌入 原生view1 info.plist文件设置iOS端的UiKitView目前还只是preview状态, 默认是不支持的, 需要手动打开开关, 在info.plist文件中新增一行io.flutter.embedded_views_preview为true. 如果不添加,会抛出如下异常: Trying to embed a platform view but the PrerollContext does not support embedding创建类 FlutterIosTextLabel 并实现FlutterPlatformView 协议 FlutterIosTextLabel.h #import #importNS_ASSUME_NONNULL_BEGIN //实现协议FlutterPlatformView@interface FlutterIosTextLabel : NSObject -(instancetype)initWithWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args binaryMessenger:(NSObject*)messenger;@end NS_ASSUME_NONNULL_END FlutterIosTextLabel.m #import "FlutterIosTextLabel.h"@implementation FlutterIosTextLabel{ //FlutterIosTextLabel 创建后的标识 int64_t _viewId; UILabel * _uiLabel; //消息回调 FlutterMethodChannel* _channel;} //在这里只是创建了一个UILabel-(instancetype)initWithWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id)args binaryMessenger:(NSObject *)messenger{ if ([super init]) { if (frame.size.width==0) { frame=CGRectMake(frame.origin.x, frame.origin.y, [UIScreen mainScreen].bounds.size.width, 22); } _uiLabel =[[UILabel alloc] initWithFrame:frame]; _uiLabel.textColor=[UIColor redColor]; _uiLabel.text=@"ios 原生 uilabel "; _uiLabel.font=[UIFont systemFontOfSize:14]; _uiLabel.textAlignment=NSTextAlignmentCenter; _uiLabel.backgroundColor=[UIColor grayColor]; _viewId = viewId; } return self; } - (nonnull UIView *)view { return _uiLabel;} @end 2 创建PlatformViewFactoryFlutterIosTextLabelFactory.h #import #import NS_ASSUME_NONNULL_BEGIN@interface FlutterIosTextLabelFactory : NSObject - (instancetype)initWithMessenger:(NSObject*)messager; @end NS_ASSUME_NONNULL_END FlutterIosTextLabelFactory.m #import "FlutterIosTextLabelFactory.h"#import "FlutterIosTextLabel.h"@implementation FlutterIosTextLabelFactory{ NSObject*_messenger;}- (instancetype)initWithMessenger:(NSObject *)messager{ self = [super init]; if (self) { _messenger = messager; } return self;} //设置参数的编码方式 -(NSObject *)createArgsCodec{ return [FlutterStandardMessageCodec sharedInstance];} //用来创建 ios 原生view- (nonnull NSObject *)createWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args { //args 为flutter 传过来的参数 FlutterIosTextLabel *textLagel = [[FlutterIosTextLabel alloc] initWithWithFrame:frame viewIdentifier:viewId arguments:args binaryMessenger:_messenger]; return textLagel;} @end 4 创建PluginFlutterIosTextLabelPlugin.h #import #importNS_ASSUME_NONNULL_BEGIN @interface FlutterIosTextLabelPlugin :NSObject @end NS_ASSUME_NONNULL_END FlutterIosTextLabelPlugin.m #import "FlutterIosTextLabelPlugin.h"#import "FlutterIosTextLabelFactory.h"@implementation FlutterIosTextLabelPlugin + (void)registerWithRegistrar:(nonnull NSObject *)registrar { //注册插件 //注册 FlutterIosTextLabelFactory //com.flutter_to_native_test_textview 为flutter 调用此 textLabel 的标识 [registrar registerViewFactory:[[FlutterIosTextLabelFactory alloc] initWithMessenger:registrar.messenger] withId:@"com.flutter_to_native_test_textview"];} @end 4 注册4.1 创建 FlutterIosTextLabelRegistranFlutterIosTextLabelRegistran.h #import #import #import "FlutterIosTextLabelPlugin.h"NS_ASSUME_NONNULL_BEGIN@interface FlutterIosTextLabelRegistran : NSObject+ (void)registerWithRegistry:(NSObject*)registry;@end NS_ASSUME_NONNULL_END FlutterIosTextLabelRegistran.m #import "FlutterIosTextLabelRegistran.h"@implementation FlutterIosTextLabelRegistran +(void)registerWithRegistry:(NSObject *)registry{ //注册插件 [FlutterIosTextLabelPlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterIosTextLabelPlugin"]];} @end 4.2 AppDelegate 中注册插件import UIKitimport Flutter@UIApplicationMain@objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { //flutter 中引用的插件通过些类来注册 GeneratedPluginRegistrant.register(with: self); ... .. //注册插件 FlutterIosTextLabelRegistran.register(with: self); return super.application(application, didFinishLaunchingWithOptions: launchOptions) }} 5 flutter页面中使用UiKitView嵌入ios 原生UILabel5.1 最简单的调用![]() ios 原生中的接收(只会接收一次) #import "FlutterIosTextLabel.h"@implementation FlutterIosTextLabel{ //FlutterIosTextLabel 创建后的标识 int64_t _viewId; UILabel * _uiLabel; //消息回调 FlutterMethodChannel* _channel;} -(instancetype)initWithWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id)args binaryMessenger:(NSObject *)messenger{ if ([super init]) { .... .... //接收 初始化参数 NSDictionary *dic = args; NSString *content = dic[@"content"]; if (content!=nil) { _uiLabel.text=content; } .... .... } return self; } ... ... @end 5.3 flutter 更新 原生view 中的数据原生组件初始化的参数并不会随着setState重复赋值,可以通过MethodCall来实现更新数据。 首先让原生view组件实现MethodCallHandler接口: 在FlutterIosTextLabel 的初始化函数中 -(instancetype)initWithWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id)args binaryMessenger:(NSObject *)messenger{ if ([super init]) {... ... // 注册flutter 与 ios 通信通道 NSString* channelName = [NSString stringWithFormat:@"com.flutter_to_native_test_textview_%lld", viewId]; _channel = [FlutterMethodChannel methodChannelWithName:channelName binaryMessenger:messenger]; __weak __typeof__(self) weakSelf = self; [_channel setMethodCallHandler:^(FlutterMethodCall * call, FlutterResult result) { [weakSelf onMethodCall:call result:result]; }]; } return self; } -(void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result{ if ([[call method] isEqualToString:@"updateText"]) { //获取参数 NSDictionary *dict = call.arguments; NSString *content = dict[@"updateText"]; if (content!=nil) { _uiLabel.text=content; } }else{ //其他方法的回调 }} flutter 中调用 ios 原生view MethodChannel _channel; int viewId=0;mTextWidget = Container( height: 200, child: AndroidView( //标识 viewType: "com.flutter_to_native_test_textview", creationParams: { "content": "flutter 传入的文本内容", }, //参数的编码方式 creationParamsCodec: const StandardMessageCodec(), //view创建完成时的回调 onPlatformViewCreated: (id) { viewId = id; }, ), );更新数据 //这里设置的标识 MethodChannel('com.flutter_to_native_test_textview_$viewId');// 与ios NSString* channelName = [NSString stringWithFormat:@"com.flutter_to_native_test_textview_%lld", viewId]; 中注册的一至void clickUpdtae(){_channel = new MethodChannel('com.flutter_to_native_test_textview_$viewId'); updateTextView();}//这里的标识 updateText//与android 中接收消息的方法中//if ("updateText".equals(methodCall.method)) {...} 一至void updateTextView() async { return _channel.invokeMethod('updateText', "更新内容"); } 通过onPlatformViewCreated回调,监听原始组件成功创建,并能够在回调方法的参数中拿到当前组件的id,这个id是系统随机分配的,然后通过这个分配的id加上我们的组件名称最为前缀创建一个和组件通讯的MethodChannel,拿到channel对象之后就可以通过invokeMethod方法向原生组件发送消息了,这里这里调用的是‘updateText’这个方法,参数是一个String. 本公众号会首发系列专题文章,付费的视频课程会在公众号中免费刊登,在你上下班的路上或者是睡觉前的一刻,本公众号都是你浏览知识干货的一个小选择,收藏不如行动,在那一刻,公众号会提示你该学习了。 |
CopyRight 2018-2019 实验室设备网 版权所有 |